﻿using System;
using System.Collections.Generic;
using System.Linq;
using zijian666.Core.Abstractions;

namespace zijian666.Core
{
    /// <summary>
    /// 功能描述
    /// </summary>
    internal sealed class FeatureDescription
    {
        public FeatureDescription(object instance)
        {
            Feature = instance ?? throw new ArgumentNullException(nameof(instance));
            FeatureType = instance.GetType();
            var slotSetters = new List<ISlotSetter>();
            foreach (var item in instance.GetType().GetInterfaces())
            {
                if (item.Name == "IMultiSlot`1" && item.GetGenericTypeDefinition() == typeof(IMultiSlot<>))
                {
                    slotSetters.Add((ISlotSetter)Activator.CreateInstance(typeof(SlotSetter<>).MakeGenericType(item.GetGenericArguments())));
                }
                else if (item.Name == "ISlot`1" && item.GetGenericTypeDefinition() == typeof(ISlot<>))
                {
                    slotSetters.Add((ISlotSetter)Activator.CreateInstance(typeof(SlotSetter<>).MakeGenericType(item.GetGenericArguments())));
                }
            }
            _slotSetters = slotSetters.Distinct().ToList();

            AutoRefreshSlot = instance is IAutoRefreshSlot || _slotSetters.Any(x => x.AutoRefreshSlot(instance));
        }

        /// <summary>
        /// 功能组件
        /// </summary>
        public object Feature { get; }

        /// <summary>
        /// 功能组件类型
        /// </summary>
        public Type FeatureType { get; }

        /// <summary>
        /// 新增删除注册新组件是否自动刷新插槽
        /// </summary>
        public bool AutoRefreshSlot { get; }

        private readonly List<ISlotSetter> _slotSetters;

        /// <summary>
        /// 刷新插槽
        /// </summary>
        public void RefreshSlot()
        {
            foreach (var setter in _slotSetters)
            {
                setter.Set(Feature);
            }
        }

        public void RefreshSlot(bool force)
        {
            if (force || Feature is IAutoRefreshSlot)
            {
                RefreshSlot();
                return;
            }
            foreach (var setter in _slotSetters)
            {
                if (setter.AutoRefreshSlot(Feature))
                {
                    setter.Set(Feature);
                }
            }
        }


        public bool IsInstanceOf(Type type) => type?.IsInstanceOfType(Feature) ?? false;

        public bool IsInstanceOf<T>() => Feature is T;


        public override bool Equals(object obj) => obj is FeatureDescription description && Equals(Feature, description.Feature);

        public override int GetHashCode() => Feature.GetHashCode();

        public override string ToString() => "FeatureDescription:" + Feature.ToString();

        interface ISlotSetter
        {
            void Set(object instanc);
            bool AutoRefreshSlot(object instance);
        }

        class SlotSetter<T> : ISlotSetter
            where T : class
        {
            void ISlotSetter.Set(object instance)
            {
                if (instance is IMultiSlot<T> mslot)
                {
                    var features = FeatureManager.Gets<T>();
                    mslot.MultiSet(features);
                }
                else if (instance is ISlot<T> slot)
                {
                    var features = FeatureManager.Gets<T>();
                    foreach (var feature in features)
                    {
                        slot.Set(feature);
                    }
                }
            }
            public override bool Equals(object obj) => obj is SlotSetter<T>;

            public override int GetHashCode() => typeof(T).GetHashCode();

            public override string ToString() => base.ToString();

            public bool AutoRefreshSlot(object instance) => instance is IAutoRefreshMultiSlot<T> || instance is IAutoRefreshSlot<T>;
        }

    }
}
